package com.ejy.commons.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ejy.commons.enums.CommonEnum;
import com.ejy.commons.service.criteria.Analyze;
import com.ejy.commons.service.criteria.query.OrderBy;
import com.ejy.commons.service.criteria.query.Where;
import com.ejy.commons.service.entity.po.BasePo;
import com.ejy.commons.utils.BeanUtils;
import com.ejy.commons.utils.ClassUtils;
import com.ejy.commons.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
public abstract class BaseServiceImpl<PO, ID extends Long> implements BaseService<PO, ID> {

    private String STATE = "state";
    /**
     * 自定义 逻辑删除
     * 默认只查询state=1 有效的数据
     * 与分页用法一样
     * 先调用此方法 下一条sql 就会生效
     *
     * @Author WangYan
     * @Date 2021/6/10 16:07
     */
    private CommonEnum.StateEnum logicDelete = CommonEnum.StateEnum.VALID;
    /**
     * 自定义 返回数据长度
     * 与分页用法一样
     * 先调用此方法 下一条sql 就会生效
     *
     * @Author: 汪焰
     * @Date: 2020/7/21 18:20
     * version 1.0.0
     **/
    private int limit = 0;

    public abstract BaseMapper getBaseMapper();

    /**
     * 自定义 逻辑删除
     * 默认只查询state=1 有效的数据
     * 与分页用法一样
     * 先调用此方法 下一条sql 就会生效
     *
     * @Author WangYan
     * @Date 2021/6/10 16:07
     */
    @Override
    public void logicDelete(CommonEnum.StateEnum logicDelete) {
        this.logicDelete = logicDelete;
    }

    /**
     * 自定义 返回数据长度
     * 与分页用法一样
     * 先调用此方法 下一条sql 就会生效
     *
     * @Author: 汪焰
     * @Date: 2020/7/21 18:20
     * version 1.0.0
     **/
    @Override
    public void limit(int limit) {
        this.limit = limit;
    }

    @Override
    public int insert(PO po) {
        if (po instanceof BasePo) {
            ((BasePo) po).setCreateTime(new Date());
            ((BasePo) po).setUpdateTime(new Date());
        }
        return getBaseMapper().insert(po);
    }

    /**
     * 根据id更新非空字段
     */
    @Override
    public int update(Object params) {
        if (params instanceof BasePo) {
            ((BasePo) params).setUpdateTime(new Date());
        }
        return getBaseMapper().updateById(params);
    }

    @Override
    public PO read(ID id) {
        PO po = (PO) getBaseMapper().selectById(id);
        return po;
    }

    /**
     * read 默认PO返回类型
     */
    @Override
    public PO read(Object params) {
        return (PO) getBaseMapper().selectOne(buildQueryCondition(params));
    }

    /**
     * read 自定义返回类型
     */
    @Override
    public <VO> VO read(Object params, Class<VO> targetClass) {
        QueryWrapper<PO> wrapper = buildQueryCondition(params);
        QueryWrapper<PO> po = buildQueryParams(wrapper, targetClass);
        return BeanUtils.copyAToB(po, targetClass);
    }

    @Override
    public List<PO> list(Collection<ID> ids) {
        return getBaseMapper().selectBatchIds(ids);
    }

    /**
     * list 默认PO返回类型
     */
    @Override
    public List<PO> list(Object params) {
        QueryWrapper<PO> wrapper = buildQueryCondition(params);
        List<PO> list = getBaseMapper().selectList(wrapper);
        return list;
    }

    /**
     * list 自定义返回类型
     **/
    @Override
    public <VO> List<VO> list(Object params, Class<VO> targetClass) {
        QueryWrapper<PO> wrapper = buildQueryCondition(params);
        buildQueryParams(wrapper, targetClass);
        List<PO> list = getBaseMapper().selectList(wrapper);
        return BeanUtils.copyAListToBList(list, targetClass);
    }

    @Override
    public Integer sum(String sqlColumn, Object params) {
        // 获取合同包下所有合同的总金额之和
        QueryWrapper<PO> wrapper = buildQueryCondition(params);
        wrapper.select("IFNULL(sum(" + sqlColumn + "),0) as total ");
        List<Map<String, Object>> list = getBaseMapper().selectMaps(wrapper);
        Object total = list.get(0).get("total");
        if (total instanceof BigDecimal) {
            return ((BigDecimal) total).intValue();
        }
        return 0;
    }

    @Override
    public int count(Object params) {
        QueryWrapper<PO> wrapper = buildQueryCondition(params);
        int count = getBaseMapper().selectCount(wrapper);
        return count;
    }

    @Override
    public int count(String key, Object value) {
        QueryWrapper<PO> wrapper = new QueryWrapper<>();
        wrapper.eq(key, value);
        return count(wrapper);
    }

    private int count(QueryWrapper<PO> wrapper) {
        wrapper.eq(STATE, getLogicDeleteValue());
        return getBaseMapper().selectCount(wrapper);
    }

    /**
     * 自定义sql返回数据
     */
    private <VO> QueryWrapper<PO> buildQueryParams(QueryWrapper<PO> wrapper, Class<VO> targetClass) {
        StringBuffer stringBuffer = new StringBuffer();

        List<Field> fields = ClassUtils.getFieldAll(Collections.singletonList(targetClass));
        for (Field field : fields) {
            if (Analyze.isSelect(field)) {
                String sqlColumn = Analyze.getSqlColumn(field);
                stringBuffer.append(StringUtils.isBlank(stringBuffer.toString()) ? sqlColumn : StringUtils.COMMA + sqlColumn);
            }
        }
        wrapper.select(stringBuffer.toString());
        stringBuffer.setLength(0);
        return wrapper;
    }

    /**
     * 构建查询条件
     *
     * @Author: 汪焰
     * @Date: 2020/6/13 18:37
     * version 1.0.0
     **/
    private QueryWrapper<PO> buildQueryCondition(Object object) {
        QueryWrapper<PO> wrapper = new QueryWrapper<>();
        //自定义 返回数据长度
        if (limit > 0) {
            wrapper.last("limit 0," + limit);
            limit = 0;
        }
        //自定义 state 查询
        switch (logicDelete) {
            case ALL:
                break;
            default:
                wrapper.eq(STATE, getLogicDeleteValue());
                break;
        }
        //构建 where 条件
        buildWhereCondition(wrapper, object);
        //构建 groupBy 条件
        buildGroupByCondition(wrapper, object);
        //构建 orderBy 条件
        buildOrderByCondition(wrapper, object);
        return wrapper;
    }

    /**
     * 构建 where 条件
     *
     * @Author: 汪焰
     * @Date: 2020/6/13 18:37
     * version 1.0.0
     **/
    private void buildWhereCondition(QueryWrapper<PO> wrapper, Object object) {
        List<Where> queries = Analyze.where(object);
        if (!CollectionUtils.isEmpty(queries)) {
            List<Where> wheres = queries;
            wheres.stream().forEach(where -> {
                String sqlColumn = where.getSqlColumn();
                switch (where.getMark()) {
                    case equal:
                        wrapper.eq(sqlColumn, where.getValue());
                        break;
                    case notEqual:
                        wrapper.ne(sqlColumn, where.getValue());
                        break;
                    case like:
                        wrapper.like(sqlColumn, where.getValue());
                        break;
                    case likeRight:
                        wrapper.likeRight(sqlColumn, where.getValue());
                        break;
                    case in:
                        wrapper.in(sqlColumn, (Collection) where.getValue());
                        break;
                    case notIn:
                        wrapper.notIn(sqlColumn, where.getValue());
                        break;
                    case gt:
                        wrapper.gt(sqlColumn, where.getValue());
                        break;
                    case gte:
                        wrapper.ge(sqlColumn, where.getValue());
                        break;
                    case lt:
                        wrapper.lt(sqlColumn, where.getValue());
                        break;
                    case lte:
                        wrapper.le(sqlColumn, where.getValue());
                        break;
//                    case between:
//                        Tuple2<String, String> value = (Tuple2<String, String>) where.getValue();
//                        wrapper.between(sqlColumn, value.getT1(), value.getT2());
//                        break;
                    default:
                        log.error("BaseServiceImpl 出现异常查询枚举");
                }
            });

        }
    }

    /**
     * 构建 groupBy 条件
     *
     * @Author: 汪焰
     * @Date: 2020/6/13 18:37
     * version 1.0.0
     **/
    private void buildGroupByCondition(QueryWrapper<PO> wrapper, Object object) {
        List<String> groupBys = Analyze.groupBy(object);
        if (!groupBys.isEmpty()) {
            for (String groupBy : groupBys) {
                wrapper.groupBy(groupBy);
            }
        }
    }

    /**
     * 构建 orderBy 条件
     *
     * @Author: 汪焰
     * @Date: 2020/6/13 18:37
     * version 1.0.0
     **/
    private void buildOrderByCondition(QueryWrapper<PO> wrapper, Object object) {
        List<OrderBy> orderBys = Analyze.orderBy(object);
        if (!orderBys.isEmpty()) {
            for (OrderBy orderBy : orderBys) {
                switch (orderBy.getMark()) {
                    case asc:
                        wrapper.orderByAsc(orderBy.getSqlColumn());
                        break;
                    case desc:
                        wrapper.orderByDesc(orderBy.getSqlColumn());
                        break;
                    default:
                        log.error("BaseServiceImpl 出现异常排序枚举");
                }
            }
        }
        //因为这个系统的字段 没有规范 所以不能出现默认排序
        /*if (orderBys.isEmpty()) {
            wrapper.orderByDesc("id");
        }
        */
    }

    /**
     * 获取逻辑删除值
     * 获取完会重置状态值
     *
     * @Author WangYan
     * @Date 2021/6/11 11:01
     */
    private int getLogicDeleteValue() {
        int value = logicDelete.getValue();
        logicDelete = CommonEnum.StateEnum.VALID;
        return value;
    }
}
